<template>
	<div
		ref="ballElement"
		class="floating-ball"
		:class="{ 'half-hidden': isHalfHidden }"
		:style="positionStyle"
		@mousedown="startDrag"
		@mouseenter="onMouseEnter"
		@mouseleave="onMouseLeave"
		@touchstart="startDragTouch"
		@click="emit('ball-click')"
	>
		<!-- 悬浮球内容 -->
		<slot>?</slot>
	</div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
const emit = defineEmits(['ball-click']);

// 定义类型
interface Position {
	x: number;
	y: number;
}

interface Rect {
	width: number;
	height: number;
}

// 状态管理
const position = ref<Position>({ x: 0, y: 0 });
const dragging = ref<boolean>(false);
const isHovered = ref<boolean>(true);
const autoHideTimer = ref<number | null>(null);
const parentRect = ref<Rect | null>(null);
const ballElement = ref<HTMLElement | null>(null);

// 计算属性
const positionStyle = computed(() => {
	return {
		transform: `translate(${position.value.x}px, ${position.value.y}px)`,
		transition: dragging.value ? 'none' : 'all 0.3s ease',
		zIndex: dragging.value ? 10000 : 9999,
	};
});

const isHalfHidden = computed(() => {
	return !isHovered.value && !dragging.value;
});

// 获取父容器尺寸
const updateParentRect = () => {
	const parent = ballElement.value?.parentElement;
	if (parent) {
		parentRect.value = {
			width: parent.offsetWidth,
			height: parent.offsetHeight,
		};
	}
};

// 开始拖拽
const startDrag = (e: MouseEvent) => {
	e.preventDefault();
	e.stopPropagation();

	dragging.value = true;
	updateParentRect();

	const ballEl = ballElement.value;
	if (!ballEl) return;

	const ballWidth = ballEl.offsetWidth;
	const ballHeight = ballEl.offsetHeight;

	if (!parentRect.value) return;
	const { width: parentWidth, height: parentHeight } = parentRect.value;

	const startX = e.clientX - position.value.x;
	const startY = e.clientY - position.value.y;

	const onMove = (moveEvent: MouseEvent) => {
		moveEvent.preventDefault();
		moveEvent.stopPropagation();

		let newX = moveEvent.clientX - startX;
		let newY = moveEvent.clientY - startY;

		newX = Math.max(0, Math.min(newX, parentWidth - ballWidth));
		newY = Math.max(0, Math.min(newY, parentHeight - ballHeight));

		position.value = { x: newX, y: newY };
	};

	const onStop = () => {
		document.removeEventListener('mousemove', onMove);
		document.removeEventListener('mouseup', onStop);
		dragging.value = false;
		handleSnapToEdge();
		startAutoHideTimer();
	};

	document.addEventListener('mousemove', onMove);
	document.addEventListener('mouseup', onStop);
};

// 触摸屏支持
const startDragTouch = (e: TouchEvent) => {
	if (e.touches.length === 1) {
		const touch = e.touches[0];
		startDrag({
			...touch,
			clientX: touch.clientX,
			clientY: touch.clientY,
		} as unknown as MouseEvent);
	}
};

// 吸附边缘
const handleSnapToEdge = () => {
	if (!parentRect.value) return;

	const ballEl = ballElement.value;
	if (!ballEl) return;

	const ballWidth = ballEl.offsetWidth;
	const centerX = position.value.x + ballWidth / 2;

	const distanceLeft = centerX;
	const distanceRight = parentRect.value.width - centerX;

	if (distanceLeft < distanceRight) {
		position.value = { ...position.value, x: 0 };
	} else {
		position.value = {
			...position.value,
			x: parentRect.value.width - ballWidth,
		};
	}
};

// 启动自动隐藏
const startAutoHideTimer = () => {
	clearAutoHideTimer();
	autoHideTimer.value = window.setTimeout(() => {
		if (!isHovered.value) {
			// 自动隐藏逻辑已经在计算属性中处理
		}
	}, 3000);
};

// 清除定时器
const clearAutoHideTimer = () => {
	if (autoHideTimer.value) {
		clearTimeout(autoHideTimer.value);
		autoHideTimer.value = null;
	}
};

// 事件处理
const onMouseEnter = () => {
	isHovered.value = true;
	clearAutoHideTimer();
};

const onMouseLeave = () => {
	isHovered.value = false;
	startAutoHideTimer();
};

// 生命周期钩子
onMounted(() => {
	updateParentRect();
	window.addEventListener('resize', updateParentRect);

	if (parentRect.value) {
		const ballEl = ballElement.value;
		if (ballEl) {
			const ballWidth = ballEl.offsetWidth;
			const ballHeight = ballEl.offsetHeight;

			position.value = {
				x: parentRect.value.width - ballWidth,
				y: parentRect.value.height - ballHeight,
			};
		}
	}
});

onBeforeUnmount(() => {
	window.removeEventListener('resize', updateParentRect);
	clearAutoHideTimer();
});
</script>

<style scoped>
.floating-ball {
	position: absolute;
	width: 60px;
	height: 60px;
	border-radius: 50%;
	background: #409eff;
	color: white;
	text-align: center;
	line-height: 60px;
	cursor: grab;
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
	will-change: transform;
	z-index: 9999;
	touch-action: none; /* 禁用浏览器默认触摸行为 */
	user-select: none; /* 禁止文字选择 */
	-webkit-user-drag: none; /* 禁止iOS拖拽图片 */
}

.floating-ball.half-hidden {
	transform: translateX(-50%);
	opacity: 0.8;
}

/* 可添加悬停放大效果 */
.floating-ball:hover {
	transform: scale(1.1);
}
</style>
